﻿/*
 *   FunctionDescriptor.cs
 *   Copyright (c) 2011 - BitFox Software and Ricardo Federico Villafañes
 *   Contact: federvillaf@hotmail.com
 *   
 *   Licensing: This product is covered by Microsoft Reciprocal License (MS-RL)
 *              see https://bitfoxeval.codeplex.com/license
*/

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;

namespace BitFox.Evaluator.Functions
{
    /// <summary>
    /// Helper class to store the description of a builtin function
    /// </summary>
    public class FunctionDescriptor
    {
        /// <summary>
        /// The real list of arguments expeced by function
        /// </summary>
        ParameterInfo[] args;

        /// <summary>
        /// Function's name
        /// </summary>
        public string Name
        {
            get;
            private set;
        }

        /// <summary>
        /// The FIRST arg expected by function is an instance of 'CalculatorContext'
        /// </summary>
        public bool UseContext
        {
            get;
            private set;
        }

        /// <summary>
        /// The method that must be invoked to run the function.
        /// </summary>
        internal MethodInfo ReflectedMethod
        {
            get;
            private set;
        }

        /// <summary>
        /// The number of 'usable' argumentes expected by function. (If the first arg is of 'CalculatorContext' type, it is
        /// automatically injected by expression runner).
        /// </summary>
        public int ArgumentCount
        {
            get { return Parameters.Length; }
        }

        /// <summary>
        /// The description of 'usable' arguments. (If the first arg is of 'CalculatorContext' type, it is
        /// automatically injected by expression runner and not described in this array).
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1062"),
         SuppressMessage("Microsoft.Performance", "CA1819")]
        public ParameterInfo[] Parameters
        {
            get;
            private set;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="mInfo">The descriptor of the method that will be invoked.</param>
        public FunctionDescriptor(MethodInfo mInfo)
        {
            // Init properties
            if (mInfo == null) throw new ArgumentNullException("mInfo");
            this.Name = mInfo.Name.FoxToUpper();
            this.ReflectedMethod = mInfo;
            this.UseContext = false;

            // Extract the 'CalculatorEnvironment' arg, if the function need it.
            args = mInfo.GetParameters();
            int firstIndex = 0;
            if (args.Length > 0 && typeof(CalculatorContext).IsAssignableFrom(args[0].ParameterType))
            {
                UseContext = true;
                firstIndex = 1;
            }

            // Move the external arguments.
            var argList = new List<ParameterInfo>();
            while(firstIndex < args.Length)
                argList.Add(args[firstIndex++]);
            Parameters = argList.ToArray();
        }
    }
}
